package com.zsc.wxapp.services.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zsc.wxapp.clients.RemotePriceInfoClient;
import com.zsc.wxapp.context.BaseContext;
import com.zsc.wxapp.entity.*;
import com.zsc.wxapp.entity.dto.PricePageDTO;
import com.zsc.wxapp.entity.dto.PriceTagDTO;
import com.zsc.wxapp.exservices.Remote2;
import com.zsc.wxapp.mapper.PriceTagMapper;
import com.zsc.wxapp.mapper.UserMapper;
import com.zsc.wxapp.entity.external.PriceOverview;
import com.zsc.wxapp.entity.vo.BrandFluctuateNumVO;
import com.zsc.wxapp.entity.vo.PriceTimeVO;
import com.zsc.wxapp.mapper.PriceTimeMapper;
import com.zsc.wxapp.services.PriceTimeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;

@Service
@Slf4j
public class PriceTimeServiceImpl implements PriceTimeService {

    @Resource
    private PriceTimeMapper priceTimeMapper;
    @Resource
    private RemotePriceInfoClient remotePriceInfoClient;
    @Resource
    private UserMapper userMapper;
    @Resource
    private Remote2 remote2;
    @Resource
    private PriceTagMapper priceTagMapper;

    /**
     * 连接远程数据库,获取当天的卷烟数据
     */
    @Override
    public void getTodayPriceTime() {
        // 判断是否有当天的数据
        if (!priceTimeMapper.getPriceTime(LocalDate.now()).isEmpty()) {
            log.info("今天已经获取过数据");
            return;
        }

        //连接远程数据库,获取当天的卷烟数据
        log.info("获取今天的卷烟价格数据");
        List<PriceOverview> list = remotePriceInfoClient.getPriceOverview();

        //插入本服务的数据库中
        for (PriceOverview priceOverview : list) {

            PriceTime priceTime = PriceTime.builder()
                    .productName(priceOverview.getProductName())
                    .retailPrice(BigDecimal.valueOf(priceOverview.getRetailPrice()))
                    .directRetailPrice(BigDecimal.valueOf(priceOverview.getDirectRetailPrice()))
                    .factorySimpleName(priceOverview.getFactorySimpleName())
                    .priceTypeCode(priceOverview.getPriceTypeCode())
                    .productTypeCode(priceOverview.getProductTypeCode())
                    .productCode(priceOverview.getProductCode())
                    .build();
            log.info("priceTime:{}", priceTime.getProductName());
            priceTimeMapper.insert(priceTime);
        }
    }

    /**
     * 比较价格浮动品牌数量
     *
     * @return brandFluctuateNumVO
     */
    @Override
    public BrandFluctuateNumVO comparePricesNum() {
        getTodayPriceTime();
        LocalDate today = LocalDate.now();
        LocalDate yesterday = today.minusDays(1);

        //获取上一天的价格数据
        List<PriceTime> yesterdayPrime = priceTimeMapper.getPriceTime(yesterday);

        //获取今天的价格数据
        List<PriceTime> todayPrime = priceTimeMapper.getPriceTime(today);

        return comparePrices(yesterdayPrime, todayPrime);
    }

    /**
     * 比较价格浮动品牌数量
     *
     * @param yesterdayPrime 昨天价格数据
     * @param todayPrime     今天价格数据
     * @return brandFluctuateNumVO
     */
    private static BrandFluctuateNumVO comparePrices(List<PriceTime> yesterdayPrime, List<PriceTime> todayPrime) {
        Integer up = 0;
        Integer parity = 0;
        Integer down = 0;

        Map<String, BigDecimal> yesterdayPrimeMap = new HashMap<>();
        Map<String, BigDecimal> todayPrimeMap = new HashMap<>();

        // 构建两个映射
        yesterdayPrime.forEach(pp -> yesterdayPrimeMap.put(pp.getProductName(), pp.getRetailPrice()));
        todayPrime.forEach(pp -> todayPrimeMap.put(pp.getProductName(), pp.getRetailPrice()));

        // 检查两个映射中的价格变化
        Set<String> allKeys = new HashSet<>(yesterdayPrimeMap.keySet());
        allKeys.addAll(todayPrimeMap.keySet());

        int i = 0;

        for (String key : allKeys) {
            BigDecimal yesterdayPrice = yesterdayPrimeMap.get(key);
            BigDecimal todayPrice = todayPrimeMap.get(key);

            if (yesterdayPrice == null || todayPrice == null) {
                log.info("商品已经下架或者商品刚刚上新");
            } else if (yesterdayPrice.compareTo(todayPrice) == 0) {
                // 平价
                parity++;
            } else if (yesterdayPrice.compareTo(todayPrice) > 0) {
                // 上涨
                up++;
            } else if (yesterdayPrice.compareTo(todayPrice) < 0) {
                // 下跌
                down++;
            }
            i++;
        }

        return BrandFluctuateNumVO.builder()
                .downNum(down)
                .parityNum(parity)
                .upNum(up)
                .build();
    }

    /**
     * 管理员端获取零售价格列表
     *
     * @param pricePageDTO 条件
     * @return PageResult
     */
    @Override
    public PageInfo AdminPriceTimePage(PricePageDTO pricePageDTO) {
        PageHelper.startPage(pricePageDTO.getPageNum(), pricePageDTO.getPageSize());

        pricePageDTO.setDate(LocalDate.now());
        Page<PriceTimeVO> page = new Page<>();

        Page<PriceTime> list = priceTimeMapper.PageQuery(pricePageDTO);
        PageInfo result = new PageInfo<>(list);

        for (PriceTime priceTime : list) {
            //计算涨幅
            BigDecimal yesterdayPrice = priceTimeMapper.getPriceTimeByName(priceTime.getProductName(), LocalDate.now().minusDays(1)).getRetailPrice();
            BigDecimal fluctuationPrice = BigDecimal.ZERO;
            if (yesterdayPrice.compareTo(BigDecimal.ZERO) != 0) {
                fluctuationPrice = getRecognizedPrice(yesterdayPrice, priceTime.getRetailPrice());
                log.info("涨幅是：{}", fluctuationPrice);
            }

            //调用远程数据库，获取该烟的信息
            Product product = remote2.getCigaretteByName(priceTime.getProductName());

            //计算参考毛利率
            BigDecimal referGrossProfitMargin = BigDecimal.ZERO;
            if (product.getRetailPrice() != null && product.getRetailPrice().compareTo(BigDecimal.ZERO) != 0) {
                referGrossProfitMargin = (product.getRetailPrice().subtract(product.getWholeSalePrice())).divide(product.getRetailPrice(), 2, RoundingMode.HALF_UP);
            } else {
                log.info("该烟暂无市场零售价，无法计算参考毛利率");
            }
            //计算零售价格指数
            BigDecimal retailPriceIndex = product.getRetailPrice().divide(product.getWholeSalePrice(), 2, RoundingMode.HALF_UP);

            //处理数据
            PriceTimeVO priceTimeVO = PriceTimeVO.builder()
                    .id(priceTime.getId())
                    .productName(priceTime.getProductName())
                    .productCode(priceTime.getProductCode())
                    .retailPrice(product.getRetailPrice())
                    .fluctuationPrice(fluctuationPrice)
                    .directRetailPrice(product.getDirectRetailPrice())
                    .referGrossProfitMargin(referGrossProfitMargin)
                    .retailPriceIndex(retailPriceIndex)
                    .build();
            page.add(priceTimeVO);
        }
        result.setList(page);
        return result;
    }

    /**
     * 终端用户分页查询单日的数据，以用户订单为主
     *
     * @param pricePageDTO 条件
     * @return PageResult
     */
    @Override
    public PageInfo endUserPriceTimePage(PricePageDTO pricePageDTO) {
        pricePageDTO.setPageSize(15);

        Long userid = BaseContext.getCurrentId();
        User user = userMapper.selectUserById(userid);

        //获取用户订单中的卷烟代码
        List<String> productCodeList = new ArrayList<>();
        remote2.getLastOrderListByCustUuid(user.getCustomUuid()).forEach(orderVO -> productCodeList.add(orderVO.getProductCode()));

        pricePageDTO.setProductCodeList(productCodeList);
        pricePageDTO.setDate(LocalDate.now());

        //开始分页查询
        PageHelper.startPage(pricePageDTO.getPageNum(), pricePageDTO.getPageSize());
        List<PriceTime> list = priceTimeMapper.PageQuery(pricePageDTO);
        PageInfo result = new PageInfo<>(list);
        List<PriceTimeVO> page = new ArrayList<>();

        //处理数据
        for (PriceTime priceTime : list) {
            log.info("priceTime:{}", priceTime.getProductName());
            //计算涨幅
            log.info("获取前一天的价格数据");
//            PriceTime p = priceTimeMapper.getLastPriceTime(priceTime.getProductName(), LocalDate.now());
            BigDecimal yesterdayPrice;
            try {
                yesterdayPrice = priceTimeMapper.getPriceTimeByName(priceTime.getProductName(), LocalDate.now().minusDays(1)).getRetailPrice();
            } catch (Exception e) {
                yesterdayPrice = BigDecimal.ZERO;
            }
            BigDecimal fluctuationPrice = BigDecimal.valueOf(0.00);
            if (yesterdayPrice.compareTo(BigDecimal.ZERO) != 0 && yesterdayPrice != null) {
                fluctuationPrice = getRecognizedPrice(yesterdayPrice, priceTime.getRetailPrice());
                log.info("涨幅是：{}", fluctuationPrice);
            }

            //查询门店价格
            BigDecimal storePrice;
            PriceTagDTO priceTagDTO = PriceTagDTO.builder()
                    .userId(userid)
                    .productCode(priceTime.getProductCode())
                    .build();
            PriceTag priceTag = priceTagMapper.getPriceTag(priceTagDTO);
            if (priceTag != null) {
                storePrice = priceTag.getRecognizedPrice();
            } else {
                storePrice = BigDecimal.ZERO;
            }

            //调用远程数据库，获取该烟的信息
            Product product = remote2.getCigaretteByName(priceTime.getProductName());

            //计算参考毛利率
            BigDecimal referGrossProfitMargin = (product.getRetailPrice().subtract(product.getWholeSalePrice()))
                    .divide(product.getRetailPrice(), 2, RoundingMode.HALF_UP);

            //处理数据
            PriceTimeVO priceTimeVO = PriceTimeVO.builder()
                    .id(priceTime.getId())
                    .productName(priceTime.getProductName())
                    .retailPrice(product.getRetailPrice())
                    .fluctuationPrice(fluctuationPrice)
                    .directRetailPrice(product.getDirectRetailPrice())
                    .referGrossProfitMargin(referGrossProfitMargin)
                    .difference(priceTime.getRetailPrice().subtract(yesterdayPrice))
                    .storePrice(storePrice)
                    .productCode(priceTime.getProductCode())
                    .build();
            page.add(priceTimeVO);
        }

        result.setList(page);
        return result;
    }

    /**
     * 获取涨幅
     *
     * @param yesterdayPrice 昨天价格
     * @param todayPrice     今天价格
     * @return 涨幅
     */
    public static BigDecimal getRecognizedPrice(BigDecimal yesterdayPrice, BigDecimal todayPrice) {
        if (yesterdayPrice.compareTo(BigDecimal.ZERO) == 0) {
            //如果昨天没有数据了，直接返回0.00
            return BigDecimal.valueOf(0.00);
        }
        BigDecimal result = todayPrice.subtract(yesterdayPrice).divide(yesterdayPrice, 2, RoundingMode.HALF_UP);

        if (yesterdayPrice.compareTo(todayPrice) >= 0) {
            result = result.negate();
        }
        return result;
    }

    /**
     * 获取近日的价格情况
     *
     * @param id 卷烟id
     * @return List
     */
    @Override
    public List<PriceTimeVO> getPriceTimeList(Integer id) {
        // 根据id获取到卷烟代码
        String productCode = priceTimeMapper.getPriceTimeById(id);

        // 查询卷烟近日的价格
        List<PriceTime> list = priceTimeMapper.getPriceTimeList(productCode);

        //遍历priceTimeList，计算涨幅
        List<PriceTimeVO> priceTimeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            BigDecimal fluctuationPrice;
            // 检查是否到达了最后一个元素
            if (i + 1 < list.size()) {
                fluctuationPrice = getRecognizedPrice(list.get(i).getRetailPrice(), list.get(i + 1).getRetailPrice());
            } else {
                // 如果是最后一个元素，则设置默认值
                fluctuationPrice = BigDecimal.valueOf(0.00);
            }

            PriceTimeVO priceTimeVO = PriceTimeVO.builder()
                    .productName(list.get(i).getProductName())
                    .retailPrice(list.get(i).getRetailPrice())
                    .fluctuationPrice(fluctuationPrice)
                    .date(list.get(i).getCreateTime())
                    .build();
            priceTimeList.add(priceTimeVO);
        }
        return priceTimeList;
    }
}
